#!/usr/bin/env python

class Mapper:
    def __init__(self, classes, default):
        self.map     = {}
        self.default = default
        for csym, cls in classes.items():
            for c in cls: self.map[c  ] = csym
            if cls == "": self.map[cls] = csym

    def get(self, char): return self.map.get(char, self.default)

class LexerState:
    def __init__(self, id        ): self.id, self.trans = id, {}
    def __repr__(self) : return repr(self.id)
    def __rrepr__(self): return repr(self) + " {" + "".join([ "\n\t" + repr(t) + " : " + repr(s) for t,s in self.trans.items() ]) + "\n}"
    def setEnd  (self, key, rule ): self.trans.setdefault(key, None); self.rule = rule
    def setNext (self, key, state): self.trans[key] = state
    def next    (self, key       ): return self.trans[key]
    def token   (self, content   ): return self.rule.f(content)

class Lexer:
    def __init__(self, start, mapper):
        self.start  = start
        self.mapper = mapper
        self.next = None

    def move    (self               ): self.next = self.token()
    def look    (self               ): return self.next.type
    def symbol  (self               ): return self.next

    def open(self, reader):
        self.reader = reader
        self.move()

    def token(self):
        try:
            content = ""
            char    = self.reader.char()
            state   = self.start
            look    = state.next(self.mapper.get(char))
            while look:
                content += char
                char     = self.reader.nextchar()
                state    = look
                look     = state.next(self.mapper.get(char))
            return state.token(content)
        except KeyError : raise SyntaxError("Unexpected char " + repr(self.mapper.get(char)) + ":'" + char + "'")

    def __repr__(self): return repr(self.next) + " at " + repr(self.reader)
